"""
"""
import  Image
import ImageTk

from Tkinter import Canvas,  Entry,  StringVar,  Tk,  Toplevel
from Tkinter import NW

class iImage(object):
    """
    An image object to remember its image, tkimage and name.
    """
    
    def __init__(self,  name,  height=None,  width=None):
        """
        Create with optional resize.
        """
        self.name = name
        self.pilimage = Image.open('images/%s.png' % name)
        if height:
            self.pilimage= self.pilimage.resize((height,  width))
        self.tkimage = ImageTk.PhotoImage(self.pilimage)
        
    @property
    def image(self):
        """
        Return the bit useful for Tk
        """
        return self.tkimage
        
class iKbd(Toplevel):
    """
    """
    SQUARE= 'squarekey'
    WIDE= 'wide'
    TALL = 'tall'
    
    LEFT_KEY = ' < '
    RIGHT_KEY = ' > '
    DEL_KEY = ' -- '
    DONE_KEY= ' = '
    CANCEL_KEY= ' |< '
    
    def __init__(self,  master,  height,  width,  rows,  cols,  var):
        """
        """
        self.rows = rows
        self.cols = cols
        self.var = var
        self.xscale = width//self.cols
        self.halfx = self.xscale//2
        self.yscale = height//self.rows
        self.halfy = self.yscale//2
        self.halo = min(self.halfx,  self.halfy)
        self.layout = {} # store keys indexed by row and column
        self.normal_font=('Arial',  str(self.halfx),  'bold')
        self.big_font=('Arial',  str(3*self.xscale//4),  'bold')
        Toplevel.__init__(self,  master,  height=height,  width=width)
        self.resizable(width=False,  height=False)
        self.canvas = Canvas(self,  height=height,  width=width)
        self.canvas.pack()
        self.bind('<Button-1>',  lambda e: self.handle_key(e,  True))
        self.bind('<ButtonRelease-1>',  lambda e: self.handle_key(e,  False))        
        self.bg_image = iImage('background',  height,  width)
        self.canvas.create_image(0, 0,  image=self.bg_image.image,  anchor=NW)
        
    def add_key(self,  kind,  row,  col,  caption,  value=None):
        """
        Provide value if different to caption.
        """
        layout = self.layout
        layout.setdefault(row,  {})[col] = iImage(self.SQUARE,  # always use square image
                                                  2*self.xscale if kind==self.WIDE else self.xscale,  # stretch
                                                  2*self.yscale if kind==self.TALL else self.yscale)
        self.canvas.create_image(self.xscale*col,  self.yscale*row,  image=layout[row][col].image,  anchor=NW)
        self.canvas.create_text(self.xscale*col+(self.xscale if kind==self.WIDE else self.halfx), 
                                                 self.yscale*row+(self.yscale if kind==self.TALL else self.halfy), 
                                                 text=caption,  font=self.normal_font,  tag='char_%s'%(value if value else caption))

    def handle_key(self,  event,  on):
        """
        """
        canvas = self.canvas
        closest = canvas.find_closest(event.x,  event.y,  halo=None) #self.halo)
        if not closest:
            return
        print closest
        tags = canvas.gettags(closest[0])
        if not tags:
            return
        print tags
        key = tags[0]
        if key.startswith('char_'):
            canvas.itemconfigure(key,  font=self.big_font if on else self.normal_font)
            if '=' in key:
                self.var.set('')
            elif on:
                self.var.set(self.var.get()+key[-1])
   
class NumericKbd(iKbd):
    """
    A keyboardwith numbers on... a bit like a calculator keyboard.
    """
    
    def __init__(self,  master,  height,  var):
        """
        """
        iKbd.__init__(self,  master,  height,  4*height//5,  5,  4,  var)
        self.add_key(self.SQUARE,  0,  0,  self.CANCEL_KEY)
        self.add_key(self.SQUARE,  0,  1,  self.RIGHT_KEY)
        self.add_key(self.SQUARE,  0,  2,  self.LEFT_KEY)
        self.add_key(self.SQUARE,  0,  3,  self.DEL_KEY)
        self.add_key(self.SQUARE,  1,  0,  '7')
        self.add_key(self.SQUARE,  1,  1,  '8')
        self.add_key(self.SQUARE,  1,  2,  '9')
        self.add_key(self.SQUARE,  1,  3,  '-')
        self.add_key(self.SQUARE,  2,  0,  '4')
        self.add_key(self.SQUARE,  2,  1,  '5')
        self.add_key(self.SQUARE,  2,  2,  '6')
        self.add_key(self.SQUARE,  2,  3,  '+')
        self.add_key(self.SQUARE,  3,  0,  '1')
        self.add_key(self.SQUARE,  3,  1,  '2')
        self.add_key(self.SQUARE,  3,  2,  '3')
        self.add_key(self.TALL,  3,  3,  self.DONE_KEY)
        self.add_key(self.WIDE,  4,  0,  '0')
        self.add_key(self.SQUARE,  4,  2,  '.')
        
class iEntry(Entry):   
    """
    An entry field taking input from real keyboard or virtual keyboard. 
    """
  
    def __init__(self,  *a,  **k):
        """
        """
        self.var = StringVar()
        k['textvariable'] = self.var
        Entry.__init__(self,  *a,  **k)
        self.bind('<1>',  self.popup_kbd)
     
    def popup_kbd(self,  event):
        """
        """
        NumericKbd(self,  300,  self.var)
     
class Application(Tk):
    """
    """
    
    def __init__(self):
        """
        """
        Tk.__init__(self)
        self.geometry('100x50')
        iEntry(self).pack()
        self.mainloop()
        
if __name__ == '__main__':
    Application()
    
